
/*
 *
 * Copyright (c) 2006 P.J.Leonard
 * 
 * http://www.frinika.com
 * 
 * This file is part of Frinika.
 * 
 * Frinika is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.

 * Frinika is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with Frinika; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package uk.ac.bath.environment;

import java.util.Collection;
import java.util.Vector;
import uk.ac.bath.util.Tweakable;

/**
 *
 * Base class for the problem implementation specific stuff.
 * Each domain should implement a subclasss.
 *
 * Roles:
 *  - construct a simulation for a given machine
 *  - evaluate the fitness
 *  - provide a View for the GUI
 *
 *
 * Contract
 *
 *   setMachine(machine) sets the machine to be evaluated.
 * 
 *   tick() does the smallest step of evaluation
 *          and returns the fitness
 *
 *   typically keep ticking until you have decided what to do.
 *
 *   The subclass must provide implementations to
 *
 *    -- create a view.
 *
 *    -- initialize
 *
 *    -- get ready for the next machine
 *
 *    -- implement a tick
 *
 *
 * @author pjl
 */
public abstract class Evaluator {

    protected Collection<Tweakable> tweaks = new Vector<Tweakable>();
    //   private String clientStatus;
    private Fitness bestFitness;
    private int tickCount;
    private int evalCount;
   // private MachineIF bestMachine;
    protected MachineIF currentMachine;

    /**
     *
     * advance the simulation and return the state using the fitness.
     *
     * @return
     */
    final public Fitness tick() {
        tickCount++;
        Fitness fit = tickImpl();

        if (fit.decided()) {
            if (bestFitness == null || fit.fitness > bestFitness.fitness) {
                bestFitness = fit;
                // bestMachine = currentMachine;
            }
        }
        return fit;
    }

    final public Collection<Tweakable> getTweaks() {
        return tweaks;
    }

    /**
     *
     * 
     * @param machine
     */
    final public void setMachine(MachineIF machine) {
        evalCount++;
        currentMachine = machine;
        nextEvaluationImpl();
    }

    //  abstract protected void newResult(Fitness fit, MachineIF m);
    public String getStatus() {
        if (bestFitness != null) {
            return String.format("Evaluation : %-10d  TotalTicks: %-10d  best : %-7.2f", evalCount, tickCount, bestFitness.fitness);
        } else {
            return String.format("Evaluation : %-10d  TotalTicks: %-10d  best : null ", evalCount, tickCount);

        }
    }


    public void init() {
        //bestMachine = null;
        bestFitness = null;
        currentMachine = null;
        evalCount = 0;
        tickCount = 0;

        initImpl();
    }

    /**
     *  The client should update the returned view using view.repaint()
     *
     * @return a Panel to view the simulation
     */
    abstract public View createView();

    /**
     *
     * initial setup for all evaluations
     *    (individual setup per evaluation is done in nextEvalImpl)
     */
    protected abstract void initImpl();

    /**
     *
     *  execute a singe step of the evaluation and return the fitness
     */
    protected abstract Fitness tickImpl();

    /**
     * 
     * get ready for evaluating the next machine
     */
    protected abstract void nextEvaluationImpl();

    /**
     * menaingful mnessage about the problem setup
     * @return
     */
    public abstract String reportSetup();

}
